# -*- coding: utf-8 -*-
import re
from w.utils.general import Object
from datetime import datetime
from keyword import iskeyword

class BadArgument(ValueError):
    _str = ''

    def __str__(self):
        return self._str

class ReservedArgument(BadArgument):
    def __init__(self,argName):
        self._str = """'%s' is a reserved argument""" % argName

#IMPORTANT: all params with prefix '__' AND postfix '__' are ignored
def StaticInit(unique=True,**vargs):
    if unique:
        postfix = hash(str(datetime.now()))
    else:
        postfix = hash(tuple(sorted(vargs.items())))
    cls = type('type%s'%postfix, (object,), {})
    for n,v in vargs.items():
        if n.startswith('__') and n.endswith('__'):
            pass
        elif n in cls.__dict__:
            raise ReservedArgument(n)
        else:
            setattr(cls,n,v)
    return cls

class DynamicInit(Object):
    def __init__(self, **vargs):
        for n,v in vargs.items():
            if n in self.__dict__ or iskeyword(n):
                raise ReservedArgument(n)
            setattr(self,n,v)

class FilteredDynamicInit(Object):
    _argNameRE = re.compile('^_')
    _collector = Object()
    autoCapitalizedKeyword = True

    def __init__(self, **vargs):
        for n,v in vargs.items():
            if n in self.__dict__:
                raise ReservedArgument(n)
            nl = self._argNameRE.split(n,1)
            if len(nl) > 1:
                n = nl[1]
                if n in self._collector.__dict__ or \
                   (iskeyword(n) and not self.autoCapitalizedKeyword):
                    raise ReservedArgument(n)
                elif iskeyword(n) and self.autoCapitalizedKeyword:
                    n = n.capitalize()
                setattr(self._collector, n, v)
            else:
                setattr(self, n, v)

class DynamicAttribute(Object):
    def __getattribute__(self, name):
        if name != '__dict__' and name not in self.__dict__:
            setattr(self, name, None)
        if iskeyword(name):
            raise ReservedArgument(name)
        return object.__getattribute__(self, name)

class DynamicObject(DynamicInit, DynamicAttribute):
    pass

class FilteredDynamicObject(FilteredDynamicInit, DynamicAttribute):
    pass

DObject = DynamicObject
FDObject = FilteredDynamicObject
